<html>
<!--
Copyright 2010 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
  <script src="../../base.js"></script>
  <script>
    goog.require('goog.cssom');
    goog.require('goog.cssom.iframe.style');
    goog.require('goog.testing.jsunit');
  </script>
  <script>
    // unit tests
    var propertiesToTest = [
      'color',
      'font-family',
      'font-style',
      'font-size',
      'font-variant',
      'border-top-style',
      'border-top-width',
      'border-top-color',
      'background-color',
      'margin-bottom'
    ];

    function crawlDom(startNode, func) {
      if (startNode.nodeType != 1) { return; }
      func(startNode);
      for (var i = 0; i < startNode.childNodes.length; i++) {
        crawlDom(startNode.childNodes[i], func);
      }
    }

    function getCurrentCssProperties(node, propList) {
      var props = {};
      if (node.nodeType != 1) { return; }
      for (var i = 0; i < propList.length; i++) {
        var prop = propList[i];
        if (node.currentStyle) { // IE
          var propCamelCase = '';
          var propParts = prop.split('-');
          for (var j = 0; j < propParts.length; j++) {
            propCamelCase += propParts[j].charAt(0).toUpperCase() +
                             propParts[j].substring(1, propParts[j].length);
          }
          props[prop] = node.currentStyle[propCamelCase];
        } else { // standards-compliant browsers
          props[prop] = node.ownerDocument.defaultView.getComputedStyle(
              node, '').getPropertyValue(prop);
        }
      }
      return props;
    }

    function CssPropertyCollector(){
      var propsList = [];
      this.propsList = propsList

      this.collectProps = function(node) {
        var nodeProps = getCurrentCssProperties(node, propertiesToTest);
        if (nodeProps) { propsList.push([nodeProps, node]); }
      }
    }

    function recursivelyListCssProperties(el) {
      var collector = new CssPropertyCollector();
      crawlDom(el, collector.collectProps);
      return collector.propsList;
    }

    function testMatchCssSelector() {
      var container = document.createElement('div');
      container.className = 'container';
      var el = document.createElement('div');
      x = el;
      el.id = 'mydiv';
      el.className = 'colorful foo';
      // set some arbirtrary content
      el.innerHTML = '<div><ul><li>One</li><li>Two</li></ul></div>';
      container.appendChild(el);
      document.body.appendChild(container);

      var elementAncestry = new goog.cssom.iframe.style.NodeAncestry_(el);
      assertEquals(5, elementAncestry.nodes.length);

      // list of input/output results. Output is the index of the selector
      // that we expect to match - for example, in 'body div div.colorful',
      // 'div.colorful' has an index of 2.
      var expectedResults = [
        ['body div', [4, 1]],
        ['h1',  null],
        ['body div h1', [4, 1]],
        ['body div.colorful h1', [4, 1]],
        ['body div div', [4, 2]],
        ['body div div div', [4, 2]],
        ['body div div.somethingelse div', [4, 1]],
        ['body div.somethingelse div', [2, 0]],
        ['div.container', [3, 0]],
        ['div.container div', [4, 1]],
        ['#mydiv', [4, 0]],
        ['div#mydiv', [4, 0]],
        ['div.colorful', [4, 0]],
        ['div#mydiv .colorful', [4, 0]],
        ['.colorful', [4, 0]],
        ['body * div', [4,2]],
        ['body * *', [4,2]]
      ];
      for (var i = 0; i < expectedResults.length; i++) {
        var input = expectedResults[i][0];
        var expectedResult = expectedResults[i][1];
        var selector = new goog.cssom.iframe.style.CssSelector_(input);
        var result = selector.matchElementAncestry(elementAncestry);
        if (expectedResult == null) {
          assertEquals('Expected null result', expectedResult, result);
        } else {
          assertEquals('Expected element index for ' + input,
                       expectedResult[0],
                       result.elementIndex);
          assertEquals('Expected selector part index for ' + input,
                       expectedResult[1],
                       result.selectorPartIndex);
        }
      }
      document.body.removeChild(container);
    }

    function makeIframeDocument(iframe) {
      var doc = goog.dom.getFrameContentDocument(iframe);
      doc.open();
      doc.write('<html><head>');
      doc.write('<style>html,body { background-color: transparent; }</style>');
      doc.write('</head><body></body></html>');
      doc.close();
      return doc;
    }

    function testCopyCss() {
      for (var i = 1; i <= 4; i++) {
        var sourceElement = document.getElementById('source'+i);
        var newFrame = document.createElement('iframe');
        newFrame.allowTransparency = true;
        sourceElement.parentNode.insertBefore(newFrame,
                                              sourceElement.nextSibling);
        var doc = makeIframeDocument(newFrame);
        goog.cssom.addCssText(
            goog.cssom.iframe.style.getElementContext(sourceElement),
            new goog.dom.DomHelper(doc));
        doc.body.innerHTML = sourceElement.innerHTML;

        var oldProps = recursivelyListCssProperties(sourceElement);
        var newProps = recursivelyListCssProperties(doc.body);

        assertEquals(oldProps.length, newProps.length);
        for (var j = 0; j < oldProps.length; j++) {
          for (var k = 0; k < propertiesToTest.length; k++) {
            assertEquals('testing property ' + propertiesToTest[k],
                         oldProps[j][0][propertiesToTest[k]],
                         newProps[j][0][propertiesToTest[k]]);
          }
        }
      }
    }

    function normalizeCssText(cssText) {
      // Normalize cssText for testing purposes.
      return cssText.replace(/\s/g, '').toLowerCase();
    }

    function testAImportantInFF2() {
      var testDiv = document.getElementById('source1');
      var cssText = normalizeCssText(
          goog.cssom.iframe.style.getElementContext(testDiv));
      var color = standardizeCSSValue('color', 'red');
      var NORMAL_RULE = 'a{color:' + color;
      var FF_2_RULE = 'a{color:' + color + '!important';
      if (goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9a')) {
        assertContains(FF_2_RULE, cssText);
      } else {
        assertContains(NORMAL_RULE, cssText);
        assertNotContains(FF_2_RULE, cssText);
      }
    }

    function testCopyBackgroundContext() {
      var testDiv = document.getElementById('backgroundTest');
      var cssText = goog.cssom.iframe.style.getElementContext(testDiv,
                                                              null,
                                                              true);
      var iframe = document.createElement('iframe');
      var ancestor = document.getElementById('backgroundTest-ancestor-1');
      ancestor.parentNode.insertBefore(iframe, ancestor.nextSibling);
      iframe.style.width = '100%';
      iframe.style.height = '100px';
      iframe.style.borderWidth = '0px';
      var doc = makeIframeDocument(iframe);
      goog.cssom.addCssText(cssText, new goog.dom.DomHelper(doc));
      doc.body.innerHTML = testDiv.innerHTML;
      var normalizedCssText = normalizeCssText(cssText);
      assertTrue(
          'Background color should be copied from parent element',
          /body{[^{]*background-color:(?:rgb\(128,0,128\)|#800080)/.test(
              normalizedCssText));
      assertTrue(
          'Background image should be copied from ancestor element',
          /body{[^{]*background-image:url\(/.test(normalizedCssText));
      // Background-position can't be calculated in FF2, due to this bug:
      // http://bugzilla.mozilla.org/show_bug.cgi?id=316981
      if (!(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
        // Expected x position is:
        // originalBackgroundPositionX - elementOffsetLeft
        // 40px - (1px + 8px) == 31px
        // Expected y position is:
        // originalBackgroundPositionY - elementOffsetLeft
        // 70px - (1px + 10px + 5px) == 54px;
        assertTrue('Background image position should be adjusted correctly',
            /body{[^{]*background-position:31px54px/.test(normalizedCssText));
      }
    }

    function testCopyBackgroundContextFromIframe() {
      var testDiv = document.getElementById('backgroundTest');
      var iframe = document.createElement('iframe');
      iframe.allowTransparency = true;
      iframe.style.position = 'absolute';
      iframe.style.top = '5px';
      iframe.style.left = '5px';
      iframe.style.borderWidth = '2px';
      iframe.style.borderStyle = 'solid';
      testDiv.appendChild(iframe);
      var doc = makeIframeDocument(iframe);
      doc.body.backgroundColor = 'transparent';
      doc.body.style.margin = '0';
      doc.body.style.padding = '0';
      doc.body.innerHTML = '<p style="margin: 0">I am transparent!</p>';
      var normalizedCssText = normalizeCssText(
          goog.cssom.iframe.style.getElementContext(
              doc.body.firstChild, null, true));
      // Background properties should get copied through from the parent
      // document since the iframe is transparent
      assertTrue(
          'Background color should be copied from parent element',
          /body{[^{]*background-color:(?:rgb\(128,0,128\)|#800080)/.test(
              normalizedCssText));
      assertTrue(
          'Background image should be copied from ancestor element',
          /body{[^{]*background-image:url\(/.test(normalizedCssText));
      // Background-position can't be calculated in FF2, due to this bug:
      // http://bugzilla.mozilla.org/show_bug.cgi?id=316981
      if (!(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9'))) {
        // Image offset should have been calculated to be the same as the
        // above example, but adding iframe offset and borderWidth.
        // Expected x position is:
        // originalBackgroundPositionX - elementOffsetLeft
        // 40px - (1px + 8px + 5px + 2px) == 24px
        // Expected y position is:
        // originalBackgroundPositionY - elementOffsetLeft
        // 70px - (1px + 10px + 5px + 5px + 2px) == 47px;
        assertTrue('Background image position should be adjusted correctly',
            !!/body{[^{]*background-position:24px47px/.exec(
                normalizedCssText))
      }
      iframe.parentNode.removeChild(iframe);
    }

    function testCopyFontFaceRules() {
      var isFontFaceCssomSupported =
          goog.userAgent.WEBKIT ||
          goog.userAgent.OPERA ||
          (goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'));
      // We cannot use goog.testing.ExpectedFailures since it dynamically
      // brings in CSS which causes the background context tests to fail
      // in IE6.
      if (isFontFaceCssomSupported) {
        var cssText = goog.cssom.iframe.style.getElementContext(
            document.getElementById('cavalier'));
        assertTrue('The font face rule should have been copied correctly',
                   /@font-face/.test(cssText));
      }
    }

  </script>
  <style type="text/css">
    @import url("style_test_import.css");

    body { font-family: Verdana; }
    div { background-color: #ffc; margin: 10px 0; }
    p { margin: 10px 0; }
    .boxy { padding: 5px; background-color: #fa0; }
    .special .boxy { padding: 10px; background-color: #abef00; }
    div div strong { color: red; }
    div { line-height: 1.3; }
    .wrapper .inner-wrapper { border: 2px solid pink;}
    a { color: red; }
    #source4 { background-color: #900; }

    #backgroundTest-ancestor-1 {
      background-color: rgb(128,0,128);
    }
    #backgroundTest-ancestor-0 {
      background-image: url("../../images/blank.gif");
      background-position: 40px 70px;
      background-repeat: repeat;
      background-color: transparent;
      padding: 5px 8px;
    }
    div#backgroundTest-parent {
      border: 1px solid black;
      background-color: transparent;
    }
    div#backgroundTest {
      position: relative;
      background-color: transparent;
      height: 100px;
      margin-top: 0;
    }
  </style>
  <style type="text/css">
    .goog-presently-theme-monochrome {
      background-color: black;
      color: #CCC;
    }
   .goog-presently-theme-monochrome a {
     color: #FFF;
    }
    .goog-presently-theme-monochrome p#source4 {
      font-variant: small-caps;
    }

    .italic {
      font-style: italic;
    }
  </style>
  <style type="text/css">
    @font-face {
      font-family: Cavalier;
    }
    #cavalier {
      font-family: Cavalier;
    }
  </style>
</head>
<body>

 <div class="wrapper">

 <div class="inner-wrapper">

 <div id="source1" class="italic">
  hello world
 </div>

 <div id="source2">
  <div>Some <strong>strong</strong> text</div>
  <div class="boxy exciting">A box</div>
  <div class="inner-wrapper">A wrapper</div>
 </div>

 <div id="source3" class="special">
  Some <strong>strong</strong> text
  <div class="boxy">A box</div>
 </div>

 <div id="ancestor" class="goog-presently-theme-monochrome">
    <p id="source4" style="background-color: #900">
     Here's a link: <a href="#">my link</a>
   </p>
 </div>

 <div id="backgroundTest-ancestor-1">
   <div id="backgroundTest-ancestor-0">
    <div id="backgroundTest-parent">
      <div id="backgroundTest">
      hello
      </div>
    </div>
  </div>
</div>

<div id="cavalier"></div>
 </div>

 </div>

 <br />
</body>
</html>
